<?php
/**
 * RIP Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://rip-platform.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@rip-platform.com so we can send you a copy immediately.
 *
 * @category   RIP
 * @package    Rip\Core
 * @license    http://rip-platform.com/license/new-bsd     New BSD License
 * @version    {version}
 */


namespace Rip\Core;

/**
 * Description of Annotations
 *
 * @author sujai
 */
class AnnotationsReflector {

    /**
     * Confirms the presesnse of annotation in the doc comment
     *
     * @param mixed $obj
     * 
     * @return boolean
     */
    public static function hasClassAnnotation($obj) {
        $className = get_class($obj);

        $comments = self::__processClassDoc($className);
        return !empty($comments);
    }


    /**
     *  Confirms the presense of annotation in the specified method doc comment
     *
     * @param mixed $obj
     * @param string $methodName
     *
     * @return boolean
     */
    public static function hasMethodAnnotation($obj, $methodName) {
        $className = get_class($obj);
        $comments = self::__processMethodDoc($className, $methodName);
        return !empty($comments);
    }

    
    public static function getClassAnnotations($obj) {
        $className = get_class($obj);
        $comments = self::__classDocProcessor($className);
        return (!empty($comments) ? $comments : false);
    }    

    private static function __processClassDoc($className) {

        $rc = new \ReflectionClass($className);

        $classDocComment = $rc->getDocComment();

        return self::__processDocComment($classDocComment);

    }

    private static function __processMethodDoc($className, $methodName) {

        $rc = new \ReflectionClass($className);
        $rc = $rc->getMethod($methodName);

        $comment = $rc->getDocComment();

        return self::__processDocComment($comment);
    }

    private static function __processDocComment($docComment) {
        // Explode the doc comments by EOL (end of line)
        $commentsDoc = explode("\n", $docComment);
        //Iterate through each line
        foreach ($commentsDoc as $key => $comment) {
            // if the line has * followed by space or tab and continues with @ and capital letter it is a anotation
            if (preg_match("/\*([\s\t])+@[A-Za-z]/", $comment) == 0) {
                unset($commentsDoc[$key]);
            }
            else {
                // if the line has * followed by space or tab and continues with @ and capital letter it is a anotation
                // break the line after @ to get the class name
                $annotation = preg_split("/\*([\s\t])+@/", $comment);
                if (isset($annotation[1]) && trim($annotation[1]) != "") {
                    // The annotation classes might have paranthesis and some values with or without keys.
                    $className = explode("(", $annotation[1]);
                    if (isset($className[0]) && trim($className[0]) != "" && class_exists($className[0])) {
                        // Is the annotation class a subclass of Rip\Core\Annotation to be considered as annotation
                        $parentClasses = class_parents($className[0]);
                        if (in_array('Rip\Core\Annotation', $parentClasses)) {
                            $commentsDoc[$key] = trim($annotation[1]);

                            self::__separateParams($annotation[1]);

                            continue;
                        }
                    }
                }
                //The line has no annotation
                unset($commentsDoc[$key]);
            }
        }
        //Sort the available annotations in ascending order to reset the array index numbers
        sort($comments);
        return $commentsDoc;
    }

    private static function __separateParams($annotatedString) {
        $annotatedString = trim($annotatedString);
        $index = strpos($annotatedString, "(");
        $className = "";
        $params = array();
        if (is_bool($index) == false && $index > 0) {
            $className = substr($annotatedString, 0, $index);
            $annotatedString = substr($annotatedString, $index + 1);
            if (substr($annotatedString, -1) == ")" ) {
                $annotatedString = substr($annotatedString, 0, strlen($annotatedString) - 1);
                var_dump($annotatedString);
                $values = array();
                while (strpos($annotatedString, "=")) {
                    $key = "";
                    $value = "";
                    $location = strpos($annotatedString, "=");

                    $key = trim(substr($annotatedString, 0, $location));
                    $annotatedString = trim(substr($annotatedString, $location + 1));

                    $firstChar = $annotatedString[0];
                    if ($firstChar == '"' || $firstChar == "'") {
                        // The value is string
                        $endQuoteLocation = 1;
                        $endQuoteLocation = strpos($annotatedString, $firstChar, $endQuoteLocation);

                        while ($endQuoteLocation && isset($annotatedString[$endQuoteLocation - 1]) && $annotatedString[$endQuoteLocation - 1] == "\\" ) {
                            $endQuoteLocation = strpos($annotatedString, $firstChar, $endQuoteLocation + 1);
                        }

                        if ($endQuoteLocation == 1) {
                            //empty quotes
                            $value="";
                            $firstCommaLocation = strpos($annotatedString, ",", $endQuoteLocation + 1);
                            $annotatedString = trim(substr($annotatedString, $firstCommaLocation + 1));
                        }
                        else {
                            $value = substr($annotatedString, 1, $endQuoteLocation -1);
                            $firstCommaLocation = strpos($annotatedString, ",", $endQuoteLocation + 1);
                            //Expected Error
                            $annotatedString = trim(substr($annotatedString, $firstCommaLocation + 1));
                        }

                        $values[$key] = stripslashes($value);

                    }
                    else {
                        // The value is a constant or a number
                        $firstCommaLocation = strpos($annotatedString, ",");
                        if ($firstCommaLocation == false) {
                            $value = $annotatedString;
                        }
                        else {
                            $value = substr($annotatedString, 0, $firstCommaLocation);

                            if ( !is_nan($value) && constant($value) == NULL) {
                                $annotatedString = trim(substr($annotatedString, $firstCommaLocation + 1));
                            }
                            else if (defined($value)) {
                                $value = constant($value);
                                $annotatedString = trim(substr($annotatedString, $firstCommaLocation + 1));
                            }
                            else {
                                echo "error: value is not a constant but quotes missing";
                            }

                            
                        }

                        $values[$key] = $value;
                    }
                }
                var_dump($values);
            }
            else {
                error_log("PARANTHESIS MISSING");
            }
        }
        else {
            $className = $annotatedString;
        }

        $annotation = new $className();

        return $annotation;

//        foreach ($params as $property => $value) {
//            if (property_exists($annotation, $property)) {
//                $annotation->$property = $value;
//            }
//            else {
//                error_log("Invalid property '$property' in Annotation '$annotatedString' ", "ERROR");
//            }
//        }
    }

}